home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Programmer Power Tools
/
Programmer Power Tools.iso
/
printer
/
lptx700.arc
/
LPTX.ASM
next >
Wrap
Assembly Source File
|
1987-10-19
|
106KB
|
2,542 lines
title LPTx : Line PrinTer Output Capture Routine
page 60,132
;------------------------------------------------------------
;
; MAIN PROGRAM Version 7.00
;
; (C) Copyright 1987 by Mark DiVecchio, All Rights Reserved
; (C) Copyright 1987 by Kepa Zubeldia, All Rights Reserved
;
.xlist
;
;This program is released for use in non-commercial environments. I
;ask commercial users to register the program with a $25 copyright fee for
;each site (any number of users and computers) at which the program is used.
;
; DISCLAMER : this program tries to perform a function which is
; not supported by DOS. It will work sometime and will not work
; other times. That kind of explains why you don't see this type
; of program on the market.
; I have tested it under DOS 2.1 and DOS 3.1. Some users have
; reported trouble when running under DOS 3.x and for other users
; it works fine. USE AT YOUR OWN RISK.
;
; Mark C. DiVecchio
; 10435 Mountain Glen Terrace
; San Diego, CA 92131
; 619-566-6810
;------------------------------------------------------------
; Updates for Version 7.00 6 Oct 87
;
; Kepa Zubeldia
; Micro Consulting, Inc.
; 1650 Citizens Tower Bldg.
; Oklahoma City, OK 73106
; (405) 528-8133
;
; -Added a pop-up window that allows the control of the redirection from within
; an application program.
; -Added a switch for monochrome screens combined with color cards, to cancel
; the color generation and make the window more visible.
; -Deleted the Control-Z that was appended on the last close to a file.
; -Allow for file append when the program is called with the name of a file
; that already exists. The user still has the option of overwriting the file.
; -Added a switch to perform the append automatically.
; -Corrected the -? switch so it works.
; -Assembled with Microsoft MASM V5.0
;
; The major change is the addition of the pop-up window. The code for this was
; taken from PC Magazine, October 13, 1987, page 401, a productivity utility
; written by Jeff Prosise. It works with CGA, MGA, and EGA. With the EGA it
; will also work in 120 cols. and/or 35 or 43 line modes. Exiting the pop-up
; with an EGA leaves the cursor in underline. This is not a bug, but a feature.
;
; The pop-up window lets you turn redirection on and off from within a
; running program. You first must start LPTx from the command line as
; usual :
;
; lptx output.fil
;
; Then you can press Alt-PrtSc and a pop-up window will appear. When it
; does, the up and down arrow keys select a printer and the right and
; left arrow keys select redirection. The pop-up will state "to file"
; or "to printer" indicating the state of the redirection.
;
; Press <Enter> or <Esc> to close the window.
;
; Remember that you must start LPTx from the command line before the
; pop-up will let you turn redirection on or off.
;
;------------------------------------------------------------
; Updates for Version 6.00 18 Mar 87
;
; Added use of Timer Interrupt and Idle interrupt to permit
; writing to disk
;
; Added a switch to inhibit the output of linefeed characters when
; capturing a file. Program strips linefeed character at the
; end of the line if you turn on this switch. The switch is -l on the
; command line when you open a capture file.
;
; This version does not use the PSP swapping of previous versions.
;
;------------------------------------------------------------
; Updates for Version 5.02 19 Nov 86
;
; Added -i inactivate option. Must be only option on command line :
; lptx -i
;
; This version adds a check for DOS interuupt 21h
; function 40h for standard printer device = 0004.
;
; This addition was suggested by Dale Letterman of Seattle.
;
; Assembled using MicroSoft MASM v 4.0
;
; Program is called and used in the same way as version 3.00
;
; I now enter DOS with interrupts disabled.
;
; Added a switch to inhibit the checking of the Critical Section Flag
; Add -x to the command line the first time that you run LPTx.
;
;------------------------------------------------------------
; Updates for Version 5.00 13 May 86
;
; This version also takes over the DOS interuupt 21h and specifically
; checks for function 5.
; If that is the call, LPTx captures the character if LPTx has been
; activated. If it is a DOS call, LPTx assumes that DOS wants LPT1 since
; there is no way for the DOS call to specify a line printer number.
;
; Uses undocumented DOS int 21h calls 50h and 51h.
; 50h Set new current Program Segment Prefix(PSP) from
; segment number in BX
; 51h Get current PSP into BX.
; These calls are used before any file is opened by the resident portion
; of LPTx. There is some concern that DOS puts information about open files
; into the current PSP. Before we open our spooler file, we want to set
; the current PSP to our PSP and then restore it after the file I/O
; is complete. This idea was expressed in PC Magazine May 13, 1986 on page
; 314 in an article by Charles Petzold.
;
;
; This version 5.0 does not obsolete versions 4.0 and 3.0. Those versions
; may work under some conditions where this one does not and vica versa.
;------------------------------------------------------------
; Updates for Version 4.01 5 May 86
;
; Had an error in the way LPTx detected if it was already in memory.
; This error existed from back in version 3.00 and may have been
; the cause of this program locking up the system the very first
; time it was called.
;------------------------------------------------------------
; Updates for Version 4.0 25 April 86
;
; Assembled using MicroSoft MASM v 4.0
;
; Program is called and used in the same way as version 3.00
;
; Modified the code to check if DOS was running when the print interrupt
; occurs. If so the print request is routed back to the regular line
; printer. This will limit the use of this capture program to user
; programs which do their own output without going to DOS.
;
; In turn, this guarantees that we do re-enter DOS.
;
; The trick of saving the DOS stack was dropped in this version and
; I have resorted to another trick which I garnered from the
; following message found on info-ibmpc. I use method number 2.
;
; This version 4.0 does not obsolete version 3.0. That version may
; work under some conditions where this one does not and vica versa.
; This one worked fine for me using DOS 2.1 and 123 version 1.A.
; Will not work with Shift PrtSc.
;
comment *
Date: Thu, 30 Jan 86 08:47:51 est
Subject: File I/O from resident programs
To: allegra!seismo!usc-isib.arpa!info-ibmpc
Regarding opening up a file when you are terminate-and-stay-resident:
Be very careful when you attempt this. Many an FAT has been eaten for
lunch when I first tried doing it. Two ways that work like a charm:
1) Take over interrupt 0x28. This interrupt gets called by DOS
while its waiting for a key to be hit. Whenever it does get
called (your program should not be time critical, btw, as
this routine is never called from CPU intensive tasks), it
is safe to do with DOS what you will. (Except for certain
interruptions, such as Search First and Search Next, which
either you'll screw-up for the foreground task, or they'll
screw-up for you.)
2) Get the Critical Section Flag by issuing an int 21, with ah=0x34.
This returns a pointer to a flag in ES:BX. When this flag is
NULL, and interrupts are on, it is safe to play DOS games.
Unless you are the last program to take over the interrupt,
don't trust the flag word: many "fine" programs like SideKick
do not give you a true copy of the flag word on the stack, but
rather give a simple "pushf" after interrupts are turned off.
* ;end of comment
;
; More information from a message posted on USENIX:
;
comment *
From sdcsvax!ihnp4!timeinc!greenber Mon Jul 1 05:12:16 1985
Date: 30 Jun 85 17:12:37 CDT (Sun)
-----------------------------------------------------------
INT 21 - Internal - Return CritSectFlag Pointer (MSDOS generic)
REG AH = 34H
On Return:
ES:BX points to DOS "Critical Section Flag"
When byte pointed to is zero, DOS is supposed to be
safe to interrupt. NOT RELIABLE according to Chris
Dunford.
Examination of DOS 2.10 code in this area
indicates that the byte immediately FOLLOWING this
"Critical Section Flag" must be 00 to permit the
PRINT.COM interrupt to be called. This suggests that
checking the WORD pointed to, rather than the BYTE,
might increase reliability of the test greatly.
-----------------------------------------------------------
INT 28 - Internal routine for MSDOS
This interrupt is called from inside the "get input
from keyboard" routine in DOS, if and only if it is safe to use
INT 21 to access the disk at that time. It is used primarily by
the PRINT.COM routines, but any number of other routines could
be chained to it by saving the original vector, and calling it
with a FAR call (or just JMPing to it) at the end of the new
routine.
Until PRINT.COM installs its own routine, this
interrupt vector simply points to an IRET opcode.
-----------------------------------------------------------
* ;end of comment
;
;------------------------------------------------------------
; Updates for Version 3.0
;
; This version is fully compatible with IBM's PRINT command and
; hopefully most other print spoolers. I changed the method by which
; LPTx determines if a resident copy of itself is already in memory.
;
;------------------------------------------------------------
; This program intercepts the BIOS interrupt 17, the line printer
; interrupt. It will redirect the output of LPT1, LPT2, or LPT3 to a disk
; file. All three redirects may be active at the same time.
;
;
; Background:
;
; The basic problem with this type of program is that PC-DOS as written
; by Microsoft is not re-entrant. That means that if DOS is in control when
; the print interrupt occurs, you can not call DOS again to do some other
; function. Therefore, LPTx can not call DOS to write the captured print
; data to disk. Version 3.00 of LPTx tries to get around this by making
; PC-DOS re-entrant. Version 4.00 of LPTx gets around this by not ever
; trying to re-enter DOS.
;
;*******This Program Must be Converted to a .COM file before running ******
; Assemble with :
; masm lptx;
; link lptx;
; exe2bin lptx,lptx.com
; erase lptx.obj
; erase lptx.exe
;
;-----------------------------------------------------------------
.list
if1
%out Pass 1 - Including Macros - v6.00
;
.xlist
;-----------------------------------------------------------------
;
; Macros
;
display macro msg
mov DX,offset msg
mov AH,DISPLAY_OUTPUT
int DOS_CALL
endm
;
; For the PC-AT:
; POPF macro described in the IBM Personal Computer
; Seminar Proceedings Volume 2, Number 4 September 1984
; QUOTE
; "If the system microprocessor executes a POPF instruction in either
; the real or the virtual address mode with CPL <= IOPL, then a
; pending maskable interrupt (the INTR pin active) may be improperly
; recognized after executing the POPF instruction even if maskable
; interrupts were disabled before the POPF instruction and the value
; popped had IF=0. If the interrupt is improperly recognized, the
; interrupt is still correctly executed. This errata has no effect
; when interrupts are enabled in either real or virtual address mode.
; The errata has no effect in the virtual address mode when
; CPL > IOPL."
;
popff macro ;use POPFF instead of POPF
local popem,skip
;simulate popping flags using IRET
jmp short skip ;jump around iret
popem:
iret ;pop CS,IP,flags
skip:
push CS
call popem ;call within segment
;program will continue here
endm
;
call_dos macro ;Enter DOS with interrupts disabled
cli
int DOS_CALL
sti
endm
;
;
.list
else
%out Pass 2
endif
;-----------------------------------------------------------------
NULL equ 0
OFF equ 0
ON equ 1
EMPTY equ 0
BEL equ 7
CR equ 13
LF equ 10
DOLLAR equ '$'
COLON equ ':'
BACKSLASH equ '\'
BLANK equ ' '
DASH equ '-'
DOS_CALL equ 21h
;
REQ equ 00B91h ;LPTx request flag
ACK equ 0ABCBh ;LPTx acknowledge flag
;
BUFSIZE equ 4096 ;size of DMA buffer
DISPLAY_OUTPUT equ 9 ;for DOS call
DEF_DRIVE equ 19h
CREATE_FILE equ 3Ch
OPEN_FILE equ 3Dh
CLOSE_FILE equ 3Eh
WRITE_FILE equ 40h
DELETE_FILE equ 41h
LSEEK_FILE equ 42h
DEF_PATH equ 47h
FIND_FILE equ 4Eh
;-----------------------------------------------------------------
;
p_block struc
;
; data structure - these variables are used only in the
; memory resident copy of LPTx. BX is set to point to the offset of the
; allocation of this structure for the selected LPT
; NOTE : all of the labels in this structure are required as place
; holders even if not referenced. Used by the initialization calls
; later on.
;
active db OFF ;ON = this LPTx is on, OFF = off
handle dw NULL ;handle of disk file used by this LPT
filen db 'a:\lptx' ;space for redirection disk file name
pnum db '0' ;default to '0' just in case
db '.lst',NULL
db ' '
db ' '
bufcntr dw EMPTY ;bytes used in DMA buffer for this LPT
request db OFF ;ON indicates a write request is active
;for this LPT
prt_status db 10h ;printer status for this LPT
linefeed db ON ;ON = output a linefeed
;OFF = don't output a linefeed
buffer db BUFSIZE dup(0) ;data buffer for this LPT
;
p_block ends
;
;-----------------------------------------------------------------
;
bios_data segment at 40h
org 4Ah
crt_cols dw ? ;number of display columns
org 4Eh
crt_start dw ? ;video page offset address
org 63h
addr_6845 dw ? ;CRTC base address
org 87h
infobyte label word
ega_info db ? ;EGA info byte
bios_data ends
;
;-----------------------------------------------------------------
;
subttl Main Code
page
%out Assembling CODE Segment
cseg segment para public 'CODE'
assume CS:cseg,DS:nothing,SS:nothing
org 100h
lptx: jmp lptx_start
;
; What follows are three allocations of the Structure p_block
; One for each line printer that we can support.
; With this, all three line printers have DMA buffers and flag
; variables.
; BX is used to point to the offset of the allocation currently in use
; Line printer 1
lpt1 p_block <,,,'1'>
; Line printer 2
lpt2 p_block <,,,'2'>
; Line printer 3
lpt3 p_block <,,,'3'>
;
crit_flag db OFF ;set to ON if critical error occured
off_crit dw 0 ;save old critical error address
seg_crit dw 0
;
csect_off dw 0 ;pointer to Critical Section flag
csect_seg dw 0
cerrf_off dw 0 ;pointer to Critical Error flag
cerrf_seg dw 0
; cs_switch can be cleared by the transient copy of LPTx
cs_switch db ON ;enable check of Critical Section flag
P_NORMAL equ 90h ;Printed selected and ready
P_TIMEOUT equ 01h ;Time out
save_psp dw 0 ;Save area for User's PSP Segment Address
lptx_psp dw 0 ;Our PSP Segment Address
byte_count dw 0 ;to save DOS byte count
busy db OFF ;ON indicates write is taking place
sound db OFF ;ON uses speaker to indicate progress of LPTx
;
flag_10h db 0 ;status of interrupt 10h
flag_13h db 0 ;status of interrupt 13h
request_popup db 0 ;status of processing request
adapter db 2 ;0=MDA, 1=CGA, 2=EGA
;The following 5 lines MUST not be changed. They are dynamically set at Run Time
video_segment dw 0B800h ;video segment address
border_attr db ? ;window border attribute
text_attr db ? ;window text attribute
menu_attr db ? ;menu line attribute
video_page db ? ;current video page
cursor_mode dw ? ;cursor shape
cursor_pos dw ? ;cursor position
cursor_addr dw ? ;cursor CRTC address
new_cursor dw 0607h ;Popup cursor shape
nocolors db 0 ;monochrome only
menu_choice db 0 ;popup cursor line (0,1,2)
screen_buffer db 48 dup('SCREEN BUFFER ') ;10 * 34 * 2 bytes
color_attr db 0,0B8h,10h,07h,3fh ;black/blue,white/black,hi-white/blue
nocolor_attr db 0,0B8h,70h,07h,70h ;mono
mono_attr db 0,0B0h,70h,07h,70h
enable_values db 2Ch,28h,2Dh,29h,2Ah,2Eh,1Eh
;
; Old interrupt vector addresses
old_08h dd 0 ;address of old int 08h routine
old_09h dd 0 ;address of old int 09h routine
old_10h dd 0 ;address of old int 10h routine
old_13h dd 0 ;address of old int 13h routine
old_17h dd 0 ;address of old int 17h routine
old_21h dd 0 ;address of old int 21h routine
old_28h dd 0 ;address of old int 28h routine
;
old1Bh_segment dw ? ;old interrupt 1Bh segment
old1Bh_offset dw ? ;old interrupt 1Bh offset
old23h_segment dw ? ;old interrupt 23h segment
old23h_offset dw ? ;old interrupt 23h offset
old24h_segment dw ? ;old interrupt 24h segment
old24h_offset dw ? ;old interrupt 24h offset
;
; New Stack for Interrupt 17h
stk1_save dd 0 ;caller's stack EA
db 128 dup('STACK ')
stk1 equ this byte - 4
; New Stack for Interrupts 08h and 28h
stk2_save dd 0 ;caller's stack EA
db 128 dup('STACK ')
stk2 equ this byte - 4
; New Stack for Popup window process
stk3_ss dw 0 ;caller's stack EA
stk3_sp dw 0
db 128 dup('STACKP ')
stk3 equ this byte - 4
;
;------------------------------------------------------------------------------
; Window text
;------------------------------------------------------------------------------
;
;You will need an editor capable of handling graphics to edit the window.
;I used PC-Write, but old edlin will also work.
;Do not change the width or the depth of the window !!!
;
window db "┌──────────────LPTX──────────────┐"
db "│ │"
menuline1 db "│ lpt1: to PRINTER │"
menuline2 db "│ lpt2: to PRINTER │"
menuline3 db "│ lpt3: to PRINTER │"
db "│ │"
db "├────────────────────────────────┤"
db "│ Press: to move, to toggle,│"
db "│ <Enter> to close window. │"
db "└────────────────────────────────┘"
menufile1 db "│ lpt1: to FILE │"
menufile2 db "│ lpt2: to FILE │"
menufile3 db "│ lpt3: to FILE │"
;------------------------------------------------------------------------------
; Interrupt handler for interrupt 09h (keyboard)
;------------------------------------------------------------------------------
;
keyboard proc near
push ax
cmp CS:busy,OFF ;program already active?
jne kb_regular ; yes, skip processing this key.
in al,60h ;look at the hardware register
cmp al,55 ;is this PrtSc ?
jne kb_regular ; no, process it the old way.
sti ;set interrupt enable flag
mov ah,2 ;get keyboard shift status
int 16h
test al,8 ;Alt key also pressed?
je kb_regular ; no, process old way.
mov CS:request_popup,18 ;set request flag for 1 second.
;now, call keyboard handling routine
; to reset keyboard controller
; and as courtesy to other TSRs.
kb_regular: pop ax
jmp dword ptr CS:old_09h
keyboard endp
;
;------------------------------------------------------------------------------
;Interrupt 10h handling routine.
;------------------------------------------------------------------------------
video proc near
pushf ;push flags onto stack
inc flag_10h ;increment flag
call dword ptr CS:old_10h ;call BIOS routine
dec flag_10h ;decrement flag
iret
video endp
;
;------------------------------------------------------------------------------
;Interrupt 13h handling routine.
;------------------------------------------------------------------------------
bdisk proc far
pushf ;push flags onto stack
inc flag_13h ;set 'busy' flag
call dword ptr CS:old_13h ;call BIOS routine
pushf ;save output flags
dec flag_13h ;clear flag
popff ;restore output flags
ret 2 ;exit without destroying flags
bdisk endp
;
;
;-----------------------------------------------------------------
;
; Interrupt handler for interrupt 17h
;
int_17h proc far
sti ;interrupts on
cmp AH,3 ;AH=3 for LPTx Function
jne reg_call ;This is a regular print call
jmp ret_ack ;This is an LPTx Call
reg_call:
push BX
; set up BX to point to the data area for the requested printer
cmp DX,0 ;lpt1?
jne chk_lpt2 ;no
mov BX,offset lpt1 ;offset to LPT1
jmp short bx_set
chk_lpt2:
cmp DX,1 ;lpt2?
jne chk_lpt3 ;no
mov BX,offset lpt2 ;offset to LPT2
jmp short bx_set
chk_lpt3:
cmp DX,2 ;lpt3?
jne ill_ptr ;no - bad printer number
mov BX,offset lpt3 ;offset to LPT3
bx_set:
cmp CS:[BX].active,OFF ;are we active?
je sleep17 ;no
mov CS:[BX].prt_status,P_NORMAL ;signal ready status
cmp AH,1 ;initialize call?
je do_nix ;yes
cmp AH,2 ;status call?
je do_nix ;yes
cmp AH,0 ;print call?
jne do_nix ;no
jmp prt_17 ;we are active
do_nix: mov AH,CS:[BX].prt_status ;return print status
rtn: pop BX
iret
;
ill_ptr:mov CS:[BX].prt_status,P_TIMEOUT ;time out status
jmp do_nix
;
ret_ack: ;return acknowledgement that I'm here
; note : Change REQ & ACK from version to version so two versions
; of LPTx don't get intermixed.
cmp DX,REQ ;my flag to detect that LPTx is
;already loaded and alive.
jne ret_nak ;return a NAK
mov DX,ACK ;Memory resident LPTx answers with ACK
push CS ;now set up ES to point to the resident
pop ES ; data area
ret_nak:
iret ;return to calling program
;
sleep17:pop BX ;restore BX before we go to sleep
jmp dword ptr CS:old_17h ;jump immediate to original handler
;
prt_17:
push AX ; Start the print process.
push BX ; Character is in AL.
push CX
push DX
push DS
push ES
push SI
push DI
push BP
;
push CS ; DS is used as the segment register
pop DS ; for all data during the interrupt
;
pushf
cli
mov SI,SS
mov word ptr DS:stk1_save+2,SI ;save caller's stack pointer
mov SI,SP
mov word ptr DS:stk1_save,SI
mov SI,CS
mov SS,SI ;give me new bigger stack
mov SI,offset stk1
mov SP,SI
popff
mov DS:[BX].prt_status,P_NORMAL ;signal ready status
;prt_status is set before
;the call to prnt so that prnt
;can change it if the print to
;disk fails
call prnt ;print the character
;
pushf
cli
mov SI,word ptr DS:stk1_save
mov SP,SI ;restore caller's stack pointer
mov SI,word ptr DS:stk1_save+2
mov SS,SI
popff
pop BP
pop DI
pop SI
pop ES
pop DS
pop DX
pop CX
pop BX
pop AX
jmp do_nix
int_17h endp
;-----------------------------------------------------------------
;
; Interrupt handler for interrupt 21h
;
int_21h proc far
sti ;interrupts on
push BX
cmp AH,5 ;is this a DOS printer call?
je int_21h_5 ;yes
cmp AH,40h ;is this a DOS write call?
je int_21h_40 ;yes
jmp sleep21 ;no - go on to real DOS
; DOS Function 40h - Write to File or Device. DS:DX contains the address
;of data to write. CX contains the byte count. Return AX = byte count.
int_21h_40:
cmp BX,0004 ;Standard Printer?
jne sleep21 ;no - go on to real DOS
; set up BX to point to the data area for the requested printer
; Since we don't know what the standard printer device is, we
; use LPT1
mov BX,offset lpt1 ;offset to LPT1
cmp CS:[BX].active,OFF ;are we active?
je sleep21 ;no
push AX ;now do it
push BX
push CX
push DX
mov CS:byte_count,CX ;save byte count
mov BX,DX
;DS:BX points to buffer, CX has byte count
cmp CX,EMPTY ;check for zero byte count
je prt_21_done
loop21_40:
mov AL,[BX] ;get a character
mov AH,0 ;set up for call to interrupt 17h
int 17h ;note : int17h returns a printer status
;in AH but DOS does not define a way
;to return that status
inc BX
loop loop21_40
prt_21_done:
pop DX
pop CX
pop BX
pop AX
mov AX,CS:byte_count ;DOS returns byte count
jmp exit21 ;to return it to the user.
;
int_21h_5:
; DOS Function 5 Printer Output. The Character in DL is output to the
; standard printer device.
;
; set up BX to point to the data area for the requested printer
; Since we don't know what the standard printer device is, we
; use LPT1
mov BX,offset lpt1 ;offset to LPT1
cmp CS:[BX].active,OFF ;are we active?
je sleep21 ;no
push AX
mov AH,0 ;set up for call to interrupt 17h
mov AL,DL ;the character
int 17h
pop AX
;note : int17h returns a printer status
;in AH but DOS does not define a way
;to return it to the user.
exit21: pop BX
popff ;restore flags
clc ;never an error from us
ret ;return to caller (regular FAR return)
;
sleep21:pop BX ;restore BX before we go to sleep
jmp dword ptr CS:old_21h
int_21h endp
;
;-----------------------------------------------------------------
;
; PRNT - Print a character in AL
;
prnt proc near
push DS
cmp DS:[BX].active,OFF
je prtext ;nothing there?
push AX
cmp DS:[BX].bufcntr,BUFSIZE/2 ;buffer half full?
jne intadd ;no
;
; set write request but don't actually write anything out.
; we hope that the write can take place before the buffer fills up
;
mov DS:[BX].request,ON
cmp DS:sound,OFF ;sound on?
je intadd ;no
call horn ;sound horn to indicate buffer
; write request has been made
;
intadd: pop AX
cmp AL,LF ;is it a linefeed?
jne intnolf ;no
cmp DS:[BX].linefeed,OFF ;we are stripping linefeeds?
je prtext ;yes
intnolf:
mov DI,BX ;offset of this printer's allocation
add DI,offset lpt1.buffer ;add in offset of buffer
add DI,DS:[BX].bufcntr ;add in current byte count
mov DS:[DI],AL ;stuff it
inc DS:[BX].bufcntr
cmp DS:[BX].bufcntr,BUFSIZE ;buffer overflow?
jne prtext ;no
mov DS:[BX].active,OFF ;yes, nothing to do but deactivate
; LPTx
cmp DS:sound,OFF ;sound on?
je prtext ;no
call beep ;sound beep twice to indicate that
call beep ;we have been deactivated
prtext: pop DS
ret ;done
prnt endp
;-----------------------------------------------------------------
;
; Critical Error Handler
;
crit_int proc far ;got critical error
mov CS:crit_flag,ON ; set flag
mov AL,0 ;tells DOS to ignore the
iret ;error
crit_int endp
;-----------------------------------------------------------------
;
; Interrupt handler for interrupt 08h - clock ticks
;
; This function is installed as a handler for hardware interrupt
; type 8. It first calls the previous int 08h handler to service
; the INTEL 8259 Programmable Interrupt Controller. Then it checks
; to see if any write requests are pending. If so, it calls do_save
; and flush to write the buffer to the disk. Note that int_08h
; checks the DOS critical section flag : do_save is called only if
; DOS is available.
;
; This function protects itself against secondary invocations by
; means of the global busy flag.
;
int_08h proc far
; call original int 8h handler - ALWAYS
pushf
call dword ptr CS:old_08h
; now we can process if possible
pushf
cli
cmp CS:busy,OFF ;can we process this?
jne i08_exit ;no
cmp CS:flag_10h,0 ;video flag set?
jne dectime ;yes, then exit
cmp CS:flag_13h,0 ;disk flag set?
jne dectime ;yes, then exit
; if DOS is in its critical section, we skip the write for now and
; hope that we can write before the buffer fills
push DS ; check the critical section flag
push SI
push BX
cmp CS:cs_switch,OFF ;is checking off?
je no_cs ;yes, don't check the flag
lds SI,dword ptr CS:csect_off
cmp byte ptr [SI],OFF
jne poptime ;DOS in critical section
;this indicates that we cannot
;do any disk operations at this
;time
lds SI,dword ptr CS:cerrf_off
cmp byte ptr [SI],OFF
jne poptime ;DOS in critical error
;this indicates that we cannot
;do any disk operations at this
;time
no_cs:
cmp CS:request_popup,0
je no_popup
call do_popup
no_popup:
mov BX,offset lpt1 ;offset to LPT1
cmp DS:[BX].request,ON ;write LPT1 request?
jne no_lpt1 ;no
call do_save
no_lpt1:
mov BX,offset lpt2 ;offset to LPT2
cmp DS:[BX].request,ON ;write LPT2 request?
jne no_lpt2 ;no
call do_save
no_lpt2:
mov BX,offset lpt3 ;offset to LPT3
cmp DS:[BX].request,ON ;write LPT3 request?
jne poptime ;no
call do_save
poptime:
pop BX
pop SI
pop DS
dectime:
cmp request_popup,0
je i08_exit
dec request_popup
i08_exit:
popff
iret
int_08h endp
;-----------------------------------------------------------------
;
; Interrupt handler for interrupt 28h - idle
;
; This function is installed as a handler for hardware interrupt
; type 28h. It first calls the previous int 28h handler. Then it checks
; to see if any write requests are pending. If so, it calls do_save
; and flush to write the buffer to the disk. It does not check the
; Critical Section Flag as int 28h handlers are allowed to perform
; DOS disk I/O but not keyboard I/O since most of the time int 28h
; is called by the keyboard I/O routines when they are waiting
; for a key press.
;
; This function protects itself against secondary invocations by
; means of the global busy flag.
;
int_28h proc far
; call original int 28h handler - ALWAYS
pushf
call dword ptr CS:old_28h
; now we can process if possible
pushf
cli
cmp CS:busy,OFF ;can we process this?
jne i28_exit ;no
cmp CS:flag_10h,0 ;video flag set?
jne i28_exit ;yes, then exit
cmp CS:flag_13h,0 ;disk flag set?
jne i28_exit ;yes, then exit
cmp CS:cs_switch,OFF ;is checking off?
je i28_no_cs ;yes, don't check the flag
push DS
push SI
lds SI,dword ptr CS:cerrf_off
cmp byte ptr [SI],OFF
pop SI
pop DS
jne i28_exit ;DOS in critical error
;this indicates that we cannot
;do any disk operations at this
;time
i28_no_cs:
cmp CS:request_popup,0
je i28_nopopup
call do_popup
i28_nopopup:
call do_save
i28_exit:
popff
iret
int_28h endp
;-----------------------------------------------------------------
;
do_popup proc near
mov CS:busy,ON
mov CS:request_popup,0
cli
mov CS:stk3_ss,SS
mov CS:stk3_sp,SP
push cs
pop ss
mov sp,offset stk3
sti ;interrupts on
push AX ; Save everything
push BX
push CX
push DX
push DS
push ES
push SI
push DI
push BP
pushf
;
mov ah,15 ;get video mode and page
int 10h
cmp al,3 ;mode 0, 1, 2, or 3?
jbe pu_main1 ;yes, then continue
cmp al,7 ;mode 7?
je pu_main1 ;yes, then continue
;no, we must be in graphics, and
;I don't know how to open a window
;while in graphics...
;
;Restore registers and stack before exit.
;
do_pop_exit:
popff
pop BP
pop DI
pop SI
pop ES
pop DS
pop DX
pop CX
pop BX
pop AX
cli
mov ss,CS:stk3_ss
mov sp,CS:stk3_sp
sti ;interrupts on
mov CS:busy,OFF
ret
;
;Set DS and ES segment registers.
;
pu_main1: push cs ;set DS to code segment
pop ds
assume ds:cseg
mov ax,bios_data ;point ES to BIOS data
mov es,ax
assume es:bios_data
cmp crt_cols,80 ;at least 80 columns displayed?
jb do_pop_exit ;no, then exit
;
;Save needed video parameters.
;
mov video_page,bh ;active video page
mov ah,3 ;get cursor mode and location
int 10h
mov cursor_mode,cx
mov cursor_pos,dx
mov dx,addr_6845 ;get CRTC base address
push dx ;save it for later
mov al,14 ;specify register number
out dx,al
inc dx ;point DX to data port
in al,dx ;read high byte of address
mov ah,al ;save it
dec dx ;back to index register
mov al,15 ;specify register number
out dx,al
inc dx ;back to data port
in al,dx ;read low byte of address
mov cursor_addr,ax ;save cursor address
;
;Determine whether an EGA is present and active in the system.
;
mov ah,12h ;see if EGA is present
mov bl,10h
int 10h
cmp bl,10h ;did BL return unchanged?
je pu_main2 ;yes, then there's no EGA here
test ega_info,8 ;is the EGA currently active?
jnz pu_main2 ;no, then branch
mov adapter,2 ;set ADAPTER for EGA
push bx ;save BX
mov ax,1130h ;get number of scan lines per char
int 10h
dec cl ;form cursor definition in CX
mov ch,cl
sub ch,2
mov new_cursor,cx ;save cursor definition
mov si,offset color_attr ;point SI to color parms
pop bx ;retrieve BX
or bh,bh ;EGA attached to color monitor?
je pu_hascolor ;yes, then branch
mov si,offset mono_attr ;no, then point SI to mono parms
jmp short pu_main4
pu_hascolor: cmp nocolors,0 ;use monochrome only ?
je pu_main4 ; no, use color
mov si,offset nocolor_attr ;color card with mono screen
jmp short pu_main4
;
;Determine whether the active video adapter is a CGA or an MDA.
;
pu_main2: test addr_6845,40h ;is bit 6 of the CRTC address set?
jz pu_main3 ;no, then it's monochrome
mov adapter,1 ;set ADAPTER for a CGA
mov new_cursor,0607h ;define cursor shape
mov si,offset color_attr ;point SI to color parms
jmp short pu_hascolor
pu_main3: mov adapter,0 ;set ADAPTER for an MDA
mov new_cursor,0B0Ch ;define monochrome cursor
mov si,offset mono_attr ;point SI to mono parms
;
;Set video parameters for color or monochrome.
;
pu_main4: push cs ;set ES to the code segment
pop es
assume es:cseg
mov di,offset video_segment ;point DI to destination
mov cx,5 ;5 bytes to move
cld ;clear DF
rep movsb ;transfer the values
;
cmp adapter,1 ;disable CGA video
jne pu_main7
call disable_cga
pu_main7: call save_screen ;save memory to be overwritten
call make_screen ;open the Pop-up window
call make_status ;update status of the redirection
cmp adapter,1 ;enable CGA video
jne pu_main8
call enable_cga
pu_main8: mov ah,1 ;hide the cursor
mov ch,20h
int 10h
;
;Wait for a keystroke and return when ESC is pressed.
;
pu_mainA: call getkey ;wait for a keypress
or al,al ;extended code entered?
je pu_main12 ;yes, then branch
cmp al,32 ;SPACE pressed?
je toggle ;yes, toggle line
cmp al,13 ;ENTER pressed?
je escape ;yes, then get out
cmp al,27 ;ESC pressed?
je escape ;yes, then close window and return
jmp pu_mainA ;no, then ignore keypress
;
;An extended code was entered. Check for an Alt-character key combination.
;
pu_main12: cmp ah,72 ;UpArrow?
je upone ;yes, then process it
cmp ah,80 ;DownArrow?
je downone ;yes, then process it
cmp ah,75 ;LeftArrow?
je toggle ;toggle line
cmp ah,77 ;RightArrow?
je toggle ;toggle line
jmp pu_mainA ;return for another keypress
;
upone: cmp menu_choice,0 ;are we at the top ?
jne upone1 ; no, decrement it
mov menu_choice,3 ; yes, wrap around
upone1: dec menu_choice
call make_status ;update status of the redirection
jmp pu_mainA
downone: cmp menu_choice,2 ;are we at the bottom ?
jne downone1 ; no, increment
mov menu_choice,-1 ; yes, wrap around
downone1: inc menu_choice
call make_status ;update status of the redirection
jmp pu_mainA
toggle: call make_change ;change the state
call make_status ;update status of the redirection
jmp pu_mainA
;
;Close the Pop-up window in preparation for return.
;
escape:
cmp adapter,1 ;disable CGA video
jne esc1
call disable_cga
esc1: call restore_screen ;restore screen contents
cmp adapter,1 ;enable CGA video
jne esc2
call enable_cga
;
;Restore the cursor's former position in the BIOS data area and the CRTC.
;
esc2: mov ah,2 ;set cursor position thru BIOS
mov bh,video_page
mov dx,cursor_pos
int 10h
pop dx ;recover CRTC base address
mov cx,cursor_addr ;restore cursor address
mov al,14 ;CRTC register number
out dx,al
inc dx
mov al,ch
out dx,al ;write high byte of address
dec dx
mov al,15 ;CRTC register number
out dx,al
inc dx
mov al,cl
out dx,al ;write low byte
;
;Display the cursor, bypassing EGA cursor emulation logic, and return.
;
cmp adapter,2 ;EGA on board?
jne esc3 ;no, then branch
call show_cursor ;retain current shape
jmp do_pop_exit ; exit from popup
esc3: mov ah,1 ;restore cursor shape
mov cx,cursor_mode
int 10h
jmp do_pop_exit ; exit from popup
do_popup endp
;
;------------------------------------------------------------
;
; Writes buffer to disk
;
do_save proc near
mov CS:busy,ON ; set busy flag
push AX ; Start the print process.
push BX ; Character is in AL.
push CX
push DX
push DS
push ES
push SI
push DI
push BP
pushf
sti ;interrupts on
;
push CS ; DS is used as the segment register
pop DS ; for all data during the interrupt
;
pushf
cli
mov SI,SS
mov word ptr DS:stk2_save+2,SI ;save caller's stack pointer
mov SI,SP
mov word ptr DS:stk2_save,SI
mov SI,CS
mov SS,SI ;give me new bigger stack
mov SI,offset stk2
mov SP,SI
popff
;
; check to see if any write requests are active.
; we do not look at the active flag since the print redirection
; may have been inactivated by the time, we are able to write to
; the disk.
;
; set up BX to point to the data area for the requested printer
mov BX,offset lpt1 ;offset to LPT1
cmp DS:[BX].request,ON ;write LPT1 request?
jne c28_lpt2 ;no
call flush
mov DS:[BX].request,OFF
c28_lpt2:
mov BX,offset lpt2 ;offset to LPT2
cmp DS:[BX].request,ON ;write LPT2 request?
jne c28_lpt3 ;no
call flush
mov DS:[BX].request,OFF
c28_lpt3:
mov BX,offset lpt3 ;offset to LPT3
cmp DS:[BX].request,ON ;write LPT3 request?
jne i28_done ;no
call flush
mov DS:[BX].request,OFF
i28_done:
pushf
cli
mov SI,word ptr DS:stk2_save
mov SP,SI ;restore caller's stack pointer
mov SI,word ptr DS:stk2_save+2
mov SS,SI
popff
;
popff
pop BP
pop DI
pop SI
pop ES
pop DS
pop DX
pop CX
pop BX
pop AX
mov CS:busy,OFF
ret
do_save endp
;
;------------------------------------------------------------
;
; FLUSH - Flush print buffer to disk file
;
flush proc near
cmp DS:[BX].bufcntr,EMPTY ;buffer empty?
jne flush_buf ;no, write it to disk
ret ;exit
flush_buf:
call disk_out
ret
flush endp
;------------------------------------------------------------
;
; DISK_OUT - write to disk
;
disk_out proc near
;PSP
; push BX
; mov AH,51h ;get current PSP
; call_dos
; mov DS:save_psp,BX ;and save it
; mov BX,DS:lptx_psp ;get our PSP
; mov AH,50h
; call_dos ;set it into DOS
; pop BX
;
push ES
push DS
mov AX,DS ;set up ES
mov ES,AX
push BX
push ES
mov AX,3524h ;get old critical error vector
call_dos
mov DS:off_crit,BX
mov DS:seg_crit,ES
mov DX,offset crit_int
mov AX,2524h
call_dos ;trap critical error vector
mov DS:crit_flag,OFF ;clear critical error flag
pop ES
pop BX
mov DX,BX ;open file
add DX,offset lpt1.filen ;filename
mov AL,1 ;open for writing
mov AH,open_FILE
call_dos
mov DS:[BX].handle,AX ;file handle
jc disk_err ;error
cmp DS:crit_flag,ON ;critical error?
je disk_err ;yes
push BX
mov AH,lseek_FILE
mov AL,2 ;end of file
mov CX,0 ;offset 0
mov DX,0
mov BX,DS:[BX].handle
call_dos
pop BX
jc disk_err ;some seek error
cmp DS:crit_flag,ON ;critical error?
je disk_err ;yes
mov CX,DS:[BX].bufcntr ;buffer size
mov DX,BX ;offset of structure allocation
add DX,offset lpt1.buffer ;add offset of buffer within the
; allocation
push BX
mov AH,write_FILE
mov BX,DS:[BX].handle ;file handle
call_dos ;buffer address is DS:DX
pop BX
jnc disk_ok
cmp DS:crit_flag,ON ;critical error?
je disk_err ;yes
cmp AX,DS:[BX].bufcntr ;did DOS write it all?
je disk_ok ;yes
disk_err:
call beep ;ring bell 4 times
call beep
call beep
call beep
mov DS:[BX].active,OFF ;turn us off
mov DS:crit_flag,OFF ;clear error flag
mov DS:[BX].prt_status,P_TIMEOUT ;signal time out error
;then try to close the file
;to save what we can
jmp disk_close
disk_ok:
mov DS:[BX].bufcntr,EMPTY ;set buffer empty
disk_close:
push BX
mov BX,DS:[BX].handle
mov AH,close_FILE ;close the file
call_dos
pop BX
disk_exit:
pop DS
pop ES
push DS
lds DX,dword ptr DS:off_crit
mov AX,2524h ;restore critical error vector
call_dos
pop DS
; PSP
; push BX
; mov BX,DS:save_psp ;get user's PSP
; mov AH,50h
; call_dos ;set it back into DOS
; pop BX
;
ret
disk_out endp
;
;--------------------------------------------------------------
;
; Routine to sound the beeper
;
note equ 0a98h ;2712 = 1193180. / 440Hz
beep proc near
push AX
push BX
push CX
push DX
mov AL,0b6h ;select tim 2,lsb,msb,binary
out 43h,AL ;set up timer chip
mov AX,note ;get note
out 42h,AL ;write timer 2 count: lsb...
mov AL,AH
out 42h,AL ;...and msb
in AL,61h
mov AH,AL ;save current port setting
or AL,3
out 61h,AL ;turn speaker on
mov CX,07FFFh
beep_lp:loop beep_lp
mov AL,AH
out 61h,AL ;restore port setting
mov CX,03FFFh
beep1_lp:loop beep1_lp
pop DX
pop CX
pop BX
pop AX
ret ;return to caller
beep endp
;-------------------------------------------------------------------
;
; Routine to sound a key click
;
key_clk equ 036h ;59 = 1193180. / 20,000Hz
click proc near
push AX
push BX
push CX
mov AL,0b6h ;select tim 2,lsb,msb,binary
out 43h,AL ;set up timer chip
mov AX,key_clk ;get note
out 42h,AL ;write timer 2 count: lsb...
mov AL,AH
out 42h,AL ;...and msb
in AL,61h
mov AH,AL ;save current port setting
or AL,3
out 61h,AL ;turn speaker on
mov CX,0FFh
key_lp:loop key_lp
mov AL,AH
out 61h,AL ;restore port setting
mov CX,0FFh
key1_lp:loop key1_lp
pop CX
pop BX
pop AX
ret ;return to caller
click endp
;--------------------------------------------------------------
;
; Routine to honk the horn
;
horn proc near
push AX
push BX
push CX
push DX
mov AL,0b6h ;select tim 2,lsb,msb,binary
out 43h,AL ;set up timer chip
mov AX,2e9bh ;2712 = 1193180. / 100Hz
out 42h,AL ;write timer 2 count: lsb...
mov AL,AH
out 42h,AL ;...and msb
in AL,61h
mov AH,AL ;save current port setting
or AL,3
out 61h,AL ;turn speaker on
mov CX,07FFFh
horn_lp:loop horn_lp
mov AL,AH
out 61h,AL ;restore port setting
mov CX,03FFFh
horn1_lp:loop horn1_lp
pop DX
pop CX
pop BX
pop AX
ret ;return to caller
horn endp
;--------------------------------------------------------------------
;------------------------------------------------------------------------------
;SAVE_SCREEN saves the contents of the screen that underlie the window.
;------------------------------------------------------------------------------
video_address dw ? ;video address
linesum dw ?
;
save_screen proc near
push ds ;save DS
mov ax,bios_data ;point it to BIOS data area
mov ds,ax
assume ds:bios_data
mov ax,crt_cols ;get number of display columns
mov linesum,ax ;calculate distance from end of
sub linesum,34 ; one line to start of next
shl linesum,1 ; accounting for attribute bytes
mov bl,6 ;calculate starting addrss (6 lines)
mul bl ;result in AX
add ax,18 ;add line offset (18 columns)
shl ax,1 ;double result for attr bytes
mov si,ax ;transfer to SI
add si,crt_start ;add page offset
mov video_address,si ;save offset address
mov ds,video_segment ;then set DS to the video segment
mov di,offset screen_buffer ;point DI to storage buffer
mov cx,10 ;10 lines to save
save_screen1: push cx ;save line count
mov cx,34 ;34 characters per line
rep movsw ;transfer one line to storage
pop cx ;retrieve line count
add si,linesum ;point SI to next video line
loop save_screen1 ;loop until all lines are saved
pop ds ;restore DS
assume ds:cseg
ret ;exit
save_screen endp
;
;------------------------------------------------------------------------------
;RESTORE_SCREEN writes the stored screen image to video memory.
;------------------------------------------------------------------------------
restore_screen proc near
push es ;save ES register value
mov di,video_address ;point DI to starting video offset
mov es,video_segment ;point ES to video memory
mov si,offset screen_buffer ;point DS:SI to screen image
mov cx,10 ;10 lines to restore
restore1: push cx ;save line count
mov cx,34 ;34 characters per line
rep movsw ;restore one line
pop cx ;retrieve line count
add di,linesum ;set DI to next video line
loop restore1 ;loop until done
pop es ;restore ES
ret
restore_screen endp
;
;------------------------------------------------------------------------------
;MAKE_SCREEN writes an image of the Pop-up window to video memory.
;------------------------------------------------------------------------------
make_screen proc near
push es ;save ES
mov es,video_segment ;point ES:DI to video memory
mov di,video_address
mov si,offset window ;line 1
mov cx,34 ;do 34 characters
mov ah,border_attr ;this makes the top border
make0: lodsb
stosw
loop make0
add di,linesum
mov cx,5 ;5 lines of user text
make1: push cx
call formline
add di,linesum
pop cx
loop make1
mov cx,4 ;4 lines of instructions on bottom
mov ah,border_attr
make2: push cx
mov cx,34 ;do next 34 characters
make3: lodsb
stosw
loop make3
add di,linesum
pop cx
loop make2
pop es ;restore ES
ret
make_screen endp
;
;------------------------------------------------------------------------------
;MAKE_STATUS writes the new status of the redirection window to video memory.
;------------------------------------------------------------------------------
make_status proc near
push es ;save ES
mov es,video_segment ;point ES:DI to video memory
mov di,video_address ;this point to the beginning of w.
add di,34 * 2 ;skip over the text
add di,linesum ;skip to next line
add di,34 * 2 ;skip over the text
add di,linesum ;go down one line
cmp adapter,1 ;disable CGA video
jne msts0
call disable_cga
msts0:
mov bx,offset lpt1 ;structure #1
cmp ds:[bx].active,OFF ;printer redirected ?
mov si,offset menuline1 ; no, text says PRINTER
je msts1
mov si,offset menufile1 ; yes, text says FILE
msts1: cmp menu_choice,0 ;is this the highlighted choice?
je msts2
call formline ; no, display normal
jmp short msts3
msts2: call cursline ; yes, display highlighted
msts3: add di,linesum ;go down one line
mov bx,offset lpt2 ;structure #2
cmp ds:[bx].active,OFF ;printer redirected ?
mov si,offset menuline2 ; no, text says PRINTER
je msts4
mov si,offset menufile2 ; yes, text says FILE
msts4: cmp menu_choice,1 ;is this the highlighted choice?
je msts5
call formline ; no, display normal
jmp short msts6
msts5: call cursline ; yes, display highlighted
msts6: add di,linesum ;go down one line
mov bx,offset lpt3 ;structure #3
cmp ds:[bx].active,OFF ;printer redirected ?
mov si,offset menuline3 ; no, text says PRINTER
je msts7
mov si,offset menufile3 ; yes, text says FILE
msts7: cmp menu_choice,2 ;is this the highlighted choice?
je msts8
call formline ; no, display normal
jmp short msts9
msts8: call cursline ; yes, display highlighted
msts9:
cmp adapter,1 ;enable CGA video
jne msts10
call enable_cga
msts10:
pop es ;restore ES
ret
make_status endp
;
;------------------------------------------------------------------------------
;MAKE_CHANGE changes the status of the redirection.
;------------------------------------------------------------------------------
make_change proc near
push es ;save ES
cmp menu_choice,0 ;is this the highlighted choice?
jne mkchg1
mov bx,offset lpt1 ;structure #1
mkchg1:
cmp menu_choice,1 ;is this the highlighted choice?
jne mkchg2
mov bx,offset lpt2 ;structure #2
mkchg2:
cmp menu_choice,2 ;is this the highlighted choice?
jne mkchg3
mov bx,offset lpt3 ;structure #3
mkchg3:
cmp ds:[bx].active,OFF ;flip printer redirection
je mkchg4
mov ds:[bx].active,OFF ;turn redirection OFF
mov ax,ds:[bx].bufcntr ;look at the buffer size
or ah,al ;is there something in it ?
jz mkchg5 ; no, buffer was empty
mov ds:[bx].request,ON ; yes, request a buffer flush.
jmp short mkchg5
mkchg4: mov ax,ds:[bx].handle ;get the file handle to check it
or ah,al ;if it has ever been used.
jz mkchg5 ; no, don't activate
mov ds:[bx].active,ON ; yes, activate redirection
mkchg5: call click ;give a little noisy feedback
pop es ;restore ES
ret
make_change endp
;
;------------------------------------------------------------------------------
;FORMLINE is called by MAKE_SCREEN to help with the dirty work.
;------------------------------------------------------------------------------
formline proc near
mov ah,border_attr
lodsb
stosw
mov cx,32 ;do next 32 characters
mov ah,text_attr
form1: lodsb
stosw
loop form1
mov ah,border_attr
lodsb
stosw
ret
formline endp
;
;
;------------------------------------------------------------------------------
;CURSLINE is called by MAKE_SCREEN to help with the dirty work.
;------------------------------------------------------------------------------
cursline proc near
mov ah,border_attr
lodsb
stosw
mov cx,32 ;do next 32 characters
mov ah,menu_attr
curs1: lodsb
stosw
loop curs1
mov ah,border_attr
lodsb
stosw
ret
cursline endp
;
;
;------------------------------------------------------------------------------
;DISABLE_CGA and ENABLE_CGA disable and enable CGA video output.
;------------------------------------------------------------------------------
disable_cga proc near
mov dx,3DAh ;address of Status Register
disable1: in al,dx ;get status
test al,8 ;vertical retrace active?
je disable1 ;no, then wait
sub dx,2 ;MSR address in DX
mov al,25h ;value to disable video
out dx,al ;disable video output
ret
disable_cga endp
;
enable_cga proc near
mov ah,15 ;get video mode
int 10h
mov bx,offset enable_values ;get value to enable display
xlat ;value in AL
mov dx,3D8h ;MSR address
out dx,al ;enable video output
ret
enable_cga endp
;
;------------------------------------------------------------------------------
;GETKEY waits for a keypress and returns the keycode in AX.
;Exit: AX - keycode
;This function is careful to generate int28 for other TSR that may need them
;while the user is waiting to press a key.
;------------------------------------------------------------------------------
getkey proc near
mov ah,1 ;check keyboard buffer
int 16h
jne getkey1 ;jump if buffer contains a keycode
int 28h ;no key pressed - issue int 28h
jmp getkey ;loop back to try again
getkey1: mov ah,0 ;get keycode from buffer
int 16h
ret ;exit with keycode in AX
getkey endp
;
;
;------------------------------------------------------------------------------
;SHOW_CURSOR displays the cursor and discounts EGA cursor emulation logic.
;Entry: NEW_CURSOR - starting and ending scan lines
;------------------------------------------------------------------------------
show_cursor proc near
cmp adapter,2 ;is an EGA currently active?
jne cursor1 ;no, then branch
push es ;save ES
mov ax,bios_data ;point ES to BIOS data area
mov es,ax
assume es:bios_data
push infobyte ;save EGA info byte
or ega_info,1 ;disable EGA cursor emulation
cursor1: mov ah,1 ;display the cursor
mov cx,new_cursor
int 10h
cmp adapter,2 ;is an EGA active?
jne cursor_exit ;no, then exit
pop infobyte ;restore EGA info byte
pop es ;restore ES
assume es:nothing
cursor_exit: ret
show_cursor endp
;
;--------------------------------------------------------------------
end_res db 0
;
; This is the end of the memory resident portion of LPTx
;
;--------------------------------------------------------------------
;
; All of the following data is in the Code Segment
;
mach_type db 0
DOS_version db 0 ;Major Version Number
db 0 ;Minor Version Number
lfeed db ON ;linefeed enable switch
appending db 0 ;appending to an existing file
drive db 0 ;default drive number 0=A etc.
flag_27 db OFF ; 1=make this copy resident
wrong_dos db 'DOS 2.0 or later required for LPTx',LF,CR,DOLLAR
up_msg db 'LPTx - Line Printer Redirection Program - V7.00'
db LF,CR,' Copyright 1987 Mark C. DiVecchio'
db LF,CR,' Copyright 1987 Kepa Zubeldia',LF,CR
db DOLLAR
lptx_resident db LF,CR,'Resident Portion of LPTx Loaded',LF,CR
db 'The pop-up window will be activated by Alt-PrtSc'
db LF,LF,CR
db DOLLAR
lptx_err_3 db 'Could not delete file',LF,CR,DOLLAR
lptx_over db CR,LF,'File already exists. Do you want to overwrite '
db 'it? (y or n) :',DOLLAR
lptx_nc db 'File selection canceled',CR,LF,DOLLAR
lptx_lf db 'Stripping Linefeed Characters',CR,LF,DOLLAR
lptx_sd_on db 'Sound Enabled',CR,LF,DOLLAR
lptx_mono db 'Monochrome only, graphic card ignored',CR,LF,DOLLAR
lptx_cs_off db 'Critical Section Checking Disabled',CR,LF,DOLLAR
lptx_del db 'File is being overwritten',LF,CR,DOLLAR
lptx_cr db LF,CR,DOLLAR
lptx_bad db 'Invalid Option',LF,CR
db 'Calling sequence:',LF,CR
db 'lptx [?] [-m] [-x] [-l] [-i] {-1,-2,-3} {-c -o -a <d:[pathname]filename>}'
db LF,CR,DOLLAR
lptx_on db LF,CR,'Redirection started. Disk file opened.'
db LF,CR,DOLLAR
lptx_off db LF,CR,'Redirection ended. Disk file closed.'
db LF,CR,DOLLAR
lptx_creat db 'Could not create the disk file',LF,CR,DOLLAR
lptx_open db 'Could not open the disk file',LF,CR,DOLLAR
lptx_gone db LF,'LPTx - Resident portion inactivated',CR,LF,DOLLAR
; HELP screen
help_msg db LF,CR,'Calling sequence : ',LF,LF,CR
db 'LPTx [?] [-m] [-x] [-l] [-i] -p -f <[d:][\pathname\pathname]filename>'
db LF,LF,CR
db ' where p = printer number : 1, 2, or 3',LF,CR
db ' f = function : o for open a print file'
db LF,CR
db ' a for append to a print file'
db LF,CR
db ' c for close a print file'
db LF,CR
db ' drive letter & pathname are optional'
db LF,CR
db ' m = monochrome mode only, even with graphics cards'
db LF,CR
db ' x = disable check of Critical Section Flag'
db LF,CR
db ' l = strip Linefeed characters from output'
db LF,CR
db ' i = inactivate LPTx',LF,CR
db ' defaults : p = 1',LF,CR
db ' f = o',LF,CR
db ' The pop-up window is activated with Alt-PrtSc'
db LF,CR
db DOLLAR
;
stat_stat db CR,LF,'LPTx Status :',CR,LF,DOLLAR
stat_lp db 'lpt'
stat_ptr db ' : ',DOLLAR
stat_off db ' not redirected',CR,LF,DOLLAR
stat_dir db ' redirected to disk file '
stat_fn db 60 dup (BLANK)
;
yn_max db 2 ;max # of char
yn_act db 0
yn_in db 2 dup (0)
;
;--------------------------------------------------------------------
;
; This is the main routine which is executed each time that LPTx is
; called. In this routine, DS points to the data segment which is
; transient. ES points to the data segment which is permanently
; resident. ES:BX points to the data structure for the selected
; line printer, 1, 2, or 3.
; The offsets are the same for both. If this is the first
; time that LPTx is run, then ES=DS.
;
lptx_start:
push DS ;Save DS
xor AX,AX ;clear AX for return IP
push AX ;put 0 on stack
;
;to check for machine type look at
; F000:FFFE ; I don't use this currently
; = FF IBM PC
; = FE IBM XT or Portable
; = FD IBM PCjr
; = FC IBM PC AT
; = F9 IBM Convertible
mov AX,0F000h
mov ES,AX
mov BX,0FFFEh
mov CL,ES:[BX] ;get machine type
mov mach_type,CL ;save machine type
;
;PSP
mov lptx_psp,DS ;put away our PSP Segment address
;
; get the DOS version number
; returns zero for pre DOS 2.0 releases
mov AH,30h
int DOS_CALL ;call DOS
mov word ptr DOS_version,AX
; Requires at least version 2.0 and may or may not work
; with versions above 2.1
cmp DOS_version,2 ;is it DOS 2.+
jge dos_ok ;yes
display wrong_dos ;print error message
mov AH,0
int DOS_CALL ;terminate
dos_ok: mov AH,def_drive ;get current default drive
int DOS_CALL
mov drive,AL ;save the drive number
display up_msg ;print program ID
mov flag_27,OFF ;to not make resident
; is a copy of LPTx already resident in memory?
mov DX,REQ ;check if LPTx is already resident
mov AH,3 ;get status - special call
int 17h ;call int 17h - BIOS
cmp DX,ACK ;my handler sets DX to ACK
;and sets ES
je in_core ;LPTx is resident - ES loaded with
; segment address
mov flag_27,ON ;to make this copy resident
push CS
pop ES ;set ES to CS for segment address
mov AL,drive
add AL,'a' ;make it a letter
mov BX,offset lpt1
mov ES:[BX].filen,AL ;put it into the filename
mov BX,offset lpt2
mov ES:[BX].filen,AL ;put it into the filename
mov BX,offset lpt3
mov ES:[BX].filen,AL ;put it into the filename
; ----------------------------------------------------
in_core: ;ES is ok
; ES now points to resident data area
; set up ES:BX to point to default data structure
mov BX,offset lpt1 ;offset - default to LPT1
;get options and file name
;scan input line for line printer number
mov SI,81h ;starting offset
mov CL,DS:80h ;length of input line
mov CH,0
cmp CX,0 ;nothing?
jne cont_scan ;no
jmp make_res ;yes, then just make LPTx resident
;if it isn't already
;
; [?]
; HELP printer
;
help: display help_msg ;display the HELP screen
jmp bail_out
;
; [-m]
; Monochrome monitor, even on graphic card
;
mono_only:
mov ES:nocolors,1
display lptx_mono
jmp short inp_ret
;
; [-a]
; appending to a file, similar to open.
;
append:
mov appending,1
jmp file_op
;
;
cont_scan:
cmp byte ptr DS:[SI],'?' ;a ? ?
je help ;yes
cmp byte ptr DS:[SI],dash ;a dash ?
je got_opt ;yes
cmp byte ptr DS:[SI],CR ;a carriage return?
je scan_done ;yes
cmp byte ptr DS:[SI],BLANK ;a blank?
je inp_ret ;yes
jmp no_b ;assume that we got a file name
;without the -o option
inp_ret:
inc SI ;ignore blanks
loop cont_scan ;continue to scan
;
; Scan of whole line is complete without a "-o", "-a", "-c" or filename
scan_done:
jmp make_res
;
got_opt: ;we got an option
inc SI ;to option
cmp byte ptr DS:[SI],'1' ;LPT1?
jne chk_2
mov BX,offset lpt1 ;offset from ES
jmp short inp_ret
chk_2: cmp byte ptr DS:[SI],'2' ;LPT2?
jne chk_3
mov BX,offset lpt2 ;offset from ES
jmp short inp_ret
chk_3: cmp byte ptr DS:[SI],'3' ;LPT3?
jne chk_fil
mov BX,offset lpt3 ;offset from ES
jmp short inp_ret
chk_fil: ;is it file?
cmp byte ptr DS:[SI],'?' ;help ?
je help ;yes
cmp byte ptr DS:[SI],'o' ;open a file
je file_op ;yes
cmp byte ptr DS:[SI],'a' ;append to a file
je append ;yes
cmp byte ptr DS:[SI],'c' ;close a file
je file_cl ;yes
cmp byte ptr DS:[SI],'m' ;monochrome only ?
je mono_only ;yes
cmp byte ptr DS:[SI],'x' ;inhibit check for Critical Section?
je cs_check_off ;yes
cmp byte ptr DS:[SI],'l' ;linefeed switch ?
je lf_off ;yes
cmp byte ptr DS:[SI],'s' ;enable sound?
je sound_on ;yes
cmp byte ptr DS:[SI],'i' ;inactivate?
jne bad_opt
jmp inactivate
bad_opt:
display lptx_bad ;incorrect option
jmp nor_ex
;
; [-x]
; turn OFF Critical Section check
;
cs_check_off:
mov ES:cs_switch,OFF
display lptx_cs_off
jmp inp_ret
;
;[-l]
; Turn linefeeds off in captured file
;
lf_off: mov lfeed,OFF ;turn LFs off
display lptx_lf
jmp inp_ret ;continue the scan
;
; [-s]
; turn ON Sound
;
sound_on:
mov ES:sound,ON
display lptx_sd_on
jmp inp_ret
;
; [-c]
; close output file
;
file_cl:cmp ES:[BX].active,ON ;are we active?
jne no_close ;no
mov AL,1AH ;CTRL-Z
push DS
push ES
pop DS ;set DS to point to resident
;data segment
; call prnt ;print end of file mark
call flush
pop DS ;restore DS
mov ES:[BX].active,OFF ;make us inactive
display lptx_off ;redirection off message
no_close:
jmp nor_exit ;nothing to close so exit
;
; [-o]
; open a file for ouput
;
file_op: ;get the file name
inc SI ;to next chracter
cmp byte ptr DS:[SI],BLANK ;a blank?
jne no_b ;no
inc SI ;skip over blank
no_b:
; at this point, we have found a new file name. We close the old
; file if one was open
cmp ES:[BX].active,ON ;are we active?
jne no_cl ;no
mov AL,1AH ;CTRL-Z
push DS
push ES
pop DS ;set DS to point to resident
;data segment
; call prnt ;print end of file mark
call flush
pop DS ;restore DS
mov ES:[BX].active,OFF ;make us inactive
display lptx_off ;redirection off message
no_cl: mov DI,BX ;base of structure
add DI,offset lpt1.filen ;add offset of destination
push SI ;save pointer to file name
; search for a drive letter
inc SI ;should point to a colon if
;one is there
cmp byte ptr [SI],COLON ;?
je got_drive ;yes
get_drive:
mov AL,drive ;get drive letter
add AL,'a' ;make it a letter
mov ES:[DI],AL ;put it in file name
inc DI
mov byte ptr ES:[DI],COLON ;put in a colon
inc DI
jmp path_search
got_drive:
pop SI ;move pointer back to start
mov AL,[SI] ;get the given drive
mov ES:[DI],AL ;move it
sub AL,'a' ;make it a number
mov drive,AL ;save the drive number
inc SI
inc DI
mov byte ptr ES:[DI],COLON
inc DI
inc SI
push SI ;save new start pointer
path_search:
; now search for a backslash which says that a pathname was given
bk_s_lp:cmp byte ptr [SI],BACKSLASH
je got_path ;a path
cmp byte ptr [SI],CR ;end of the file name?
je get_path ;yes with no path
inc SI
jmp short bk_s_lp ;loop
get_path:
mov byte ptr ES:[DI],BACKSLASH ;create the path
inc DI
mov DL,drive ;the current drive
inc DL ;bump it for DOS
push DS
push ES
pop DS ;set up DS for DOS
mov SI,DI ;set up SI for pathname
mov AH,def_path ;get current directory
int DOS_CALL ;path goes into DS:SI
pop DS ;restore DS
cmp byte ptr ES:[SI],NULL ;null path?
je null_path ;yes - root directory
path_lp: ;now find the end of the string
cmp byte ptr ES:[SI],NULL ;null byte marks end of pathname
je end_path ;now append the file name
inc SI
jmp short path_lp
end_path:
mov byte ptr ES:[SI],BACKSLASH
inc SI
null_path:
mov DI,SI ;DI is destination
got_path:
pop SI ;restore source of filename
; pick up everything to next blank
get_lp:
mov AL,DS:[SI] ;character
mov ES:[DI],AL ;put it away
cmp AL,CR ;was it a Carriage Return?
je end_line
cmp AL,BLANK ;was it a space?
je end_line
inc SI
inc DI
jmp short get_lp ;no so get next character
end_line:
mov byte ptr ES:[DI],NULL ;zero out the CR or blank
;at the end of the filename
;it becomes an ASCIIZ string
sub DI,BX ;now take out the base and
cmp DI,offset lpt1.filen ; make sure that we got something
jne lptx_make ;file name was ok
display lptx_creat ;could not understand the file name
jmp nor_exit ;don't stay resident
nor_ex: jmp nor_exit
lptx_make:
; default DTA used by Find File is set by DOS to an offset of
; 80h into this program's Program Segment Prefix
push DS
push ES
pop DS ;uses DS:DX
mov DX,BX
add DX,offset lpt1.filen ;file name
mov AH,find_FILE
mov CX,0 ;normal files only
int DOS_CALL ;find first match
pop DS
jnc lptx_d ;file was found
jmp lptx_create ;not there - which is ok
;file already exists
lptx_d: cmp appending,1 ;are we in append mode?
je lptx_x ; yes
display lptx_over
mov DX,offset yn_max;input buffer
mov AH,0AH
int DOS_CALL
cmp yn_act,0 ;anything typed?
display lptx_cr
je lptx_x ;no - try to append
cmp yn_in,'y' ;a yes?
je lptx_d_yes ;yes
cmp yn_in,'Y' ;a yes?
je lptx_d_yes ;yes
lptx_x: push DS ;we can't overwrite, try to append
push ES
pop DS ;uses DS:DX
mov DX,BX ;base of this LPT's structure
add DX,offset lpt1.filen ;file name
mov AL,1 ;open for writing
mov AH,open_FILE
mov CX,0 ;normal files only
int DOS_CALL ;find first match
pop DS
jnc creat_ok
display lptx_open ;could not open the file
display lptx_nc
jmp nor_exit ;don't stay resident
lptx_d_yes:
display lptx_del
push DS
push ES
pop DS ;uses DS:DX
mov DX,BX
add DX,offset lpt1.filen ;file name
mov AH,delete_FILE
int DOS_CALL ;delete file
pop DS
jnc lptx_create ;ok its gone
display lptx_err_3 ;can't delete it
jmp nor_exit
lptx_create: ; create the file
push DS
push ES
pop DS ;uses DS:DX
mov DX,BX ;base of this LPT's structure
add DX,offset lpt1.filen ;file name
mov AH,create_FILE
mov CX,0 ;normal files only
int DOS_CALL ;find first match
pop DS
jnc creat_ok
display lptx_creat ;could not create the file
jmp nor_exit ;don't stay resident
creat_ok: ;now close the file
push BX
mov ES:[BX].handle,AX ;save the handle, for popup to know.
mov BX,AX ;AX was loaded by the create file
; call
mov AH,close_FILE ;close the file
int DOS_CALL
pop BX
display lptx_on
; set the program up for writing
mov ES:[BX].bufcntr,EMPTY ;set buffer empty
mov ES:[BX].active,ON ;set us on
mov AL,lfeed
mov ES:[BX].linefeed,AL ;save linefeed switch
make_res:
cmp flag_27,ON ;make this one resident?
je resident ;yes
jmp nor_exit ;no
;
resident:
push ES
push BX
; get old interrupt handler addressses
mov AL,17h ;get current vector address for 17h
mov AH,35h
int DOS_CALL
mov word ptr old_17h,BX
mov word ptr old_17h[2],ES ;save it for later use
mov AL,08h ;get current vector address for 08h
mov AH,35h
int DOS_CALL
mov word ptr old_08h,BX
mov word ptr old_08h[2],ES ;save it for later use
mov AL,09h ;get current vector address for 09h
mov AH,35h
int DOS_CALL
mov word ptr old_09h,BX
mov word ptr old_09h[2],ES ;save it for later use
mov AL,10h ;get current vector address for 10h
mov AH,35h
int DOS_CALL
mov word ptr old_10h,BX
mov word ptr old_10h[2],ES ;save it for later use
mov AL,13h ;get current vector address for 13h
mov AH,35h
int DOS_CALL
mov word ptr old_13h,BX
mov word ptr old_13h[2],ES ;save it for later use
mov AL,DOS_CALL ;get current vector address for 21h
mov AH,35h
int DOS_CALL
mov word ptr old_21h,BX
mov word ptr old_21h[2],ES ;save it for later use
mov AL,28h ;get current vector address for 28h
mov AH,35h
int DOS_CALL
mov word ptr old_28h,BX
mov word ptr old_28h[2],ES ;save it for later use
;
; Set LPTx up as the new int 17h interrupt handler
mov AX,2517h ;set interrupt vector
mov DX,offset int_17h ;BIOS printer
int DOS_CALL
;
; Set LPTx up as the new int 08h interrupt handler
mov AX,2508h ;set interrupt vector
mov DX,offset int_08h ;Timer
int DOS_CALL
;
; Set LPTx up as the new int 09h interrupt handler
mov AX,2509h ;set interrupt vector
mov DX,offset keyboard ;Keyboard
int DOS_CALL
;
; Set LPTx up as the new int 10h interrupt handler
mov AX,2510h ;set interrupt vector
mov DX,offset video ;Video
int DOS_CALL
;
; Set LPTx up as the new int 13h interrupt handler
mov AX,2513h ;set interrupt vector
mov DX,offset bdisk ;Disk
int DOS_CALL
;
; Set LPTx up as the new int 21h interrupt handler
; mov AX,2521h ;set interrupt vector
; mov DX,offset int_21h ;DOS Functions
; int DOS_CALL
;
; Set LPTx up as the new int 28h interrupt handler
mov AX,2528h ;set interrupt vector
mov DX,offset int_28h ;Idle
int DOS_CALL
;
; get the address of the critical section flag
;
mov AH,34h
int DOS_CALL ;Call Special DOS interrupt
;returns pointer to critical
;section flag in ES:BX
;With DOS 2.1, this returns
;00EC:012D. I used the XRAY
;program to look at this
;byte while DOS was running.
mov csect_seg,ES ;save the pointer
mov csect_off,BX
;
; get the address of the critical error flag. This piece of code comes from
; PC Magazine, October 13, 1987, page 416, CARDFILE.ASM, by Jeff Prosise.
;
mov cerrf_seg,ES ;save the pointer for critical error
mov ax,3E80h ;CMP opcode
mov cx,2000h ;max search length
mov di,bx ;start at critical section address
ce_init4: repne scasw ;do the search
jcxz ce_init5 ;branch if search failed
cmp byte ptr es:[di+5],0BCh ;verify this is it
je ce_found ;branch if it is
jmp ce_init4 ;resume loop if it's not
ce_init5: mov cx,2000h ;search again
inc bx ;search odd addresses this time
mov di,bx
ce_init6: repne scasw ;look for the opcode
jcxz ce_notfound ;not found if loop expires
cmp byte ptr es:[di+5],0BCh ;verify this is it
je ce_found
jmp ce_init6
ce_notfound: mov ax,csect_off ;flag not found, fake it
jmp ce_end
ce_found: mov ax,es:[di] ;get flag offset address
ce_end: mov cerrf_off,ax ;save it
;
pop BX
pop ES
display lptx_resident ;resident loaded message
call stat ;display status
mov DX,offset end_res
int 27h ;terminate but stay resident
;
; Normal exit for transient copy of LPTx
nor_exit:
call stat ;display status
bail_out:
mov AH,0
int DOS_CALL ;terminate
;
; [-i]
; unhook LPTx from interrupt vectors 08h, 09h, 17h, 21h, and 28h
inactivate:
;
cmp word ptr ES:old_17h,0 ;is it sill 0?
je bail_out ;yes, we weren't installed yet
; flush all buffers
mov BX,offset lpt1
cmp ES:[BX].active,ON ;are we active?
jne no_cl1 ;no
mov AL,1AH ;CTRL-Z
push DS
push ES
pop DS ;set DS to point to resident
;data segment
; call prnt ;print end of file mark
call flush
pop DS ;restore DS
mov ES:[BX].active,OFF ;make us inactive
display lptx_off ;capturing off message
;
no_cl1:
mov BX,offset lpt2
cmp ES:[BX].active,ON ;are we active?
jne no_cl2 ;no
mov AL,1AH ;CTRL-Z
push DS
push ES
pop DS ;set DS to point to resident
;data segment
; call prnt ;print end of file mark
call flush
pop DS ;restore DS
mov ES:[BX].active,OFF ;make us inactive
display lptx_off ;capturing off message
;
no_cl2:
mov BX,offset lpt3
cmp ES:[BX].active,ON ;are we active?
jne no_cl3 ;no
mov AL,1AH ;CTRL-Z
push DS
push ES
pop DS ;set DS to point to resident
;data segment
; call prnt ;print end of file mark
call flush
pop DS ;restore DS
mov ES:[BX].active,OFF ;make us inactive
display lptx_off ;capturing off message
no_cl3:
push DS
mov DX,word ptr ES:old_17h ;original vector, offset
mov AX,word ptr ES:old_17h[2];original vector, segment
mov DS,AX
mov AX,2517h ;set interrupt vector to DS:DX
int DOS_CALL
pop DS
push DS
mov DX,word ptr ES:old_21h ;original vector, offset
mov AX,word ptr ES:old_21h[2];original vector, segment
mov DS,AX
mov AX,2521h ;set interrupt vector to DS:DX
int DOS_CALL
pop DS
push DS
mov DX,word ptr ES:old_08h ;original vector, offset
mov AX,word ptr ES:old_08h[2];original vector, segment
mov DS,AX
mov AX,2508h ;set interrupt vector to DS:DX
int DOS_CALL
pop DS
push DS
mov DX,word ptr ES:old_09h ;original vector, offset
mov AX,word ptr ES:old_09h[2] ;original vector, segment
mov DS,AX
mov AX,2509h ;set interrupt vector to DS:DX
int DOS_CALL
pop DS
push DS
mov DX,word ptr ES:old_10h ;original vector, offset
mov AX,word ptr ES:old_10h[2] ;original vector, segment
mov DS,AX
mov AX,2510h ;set interrupt vector to DS:DX
int DOS_CALL
pop DS
push DS
mov DX,word ptr ES:old_13h ;original vector, offset
mov AX,word ptr ES:old_13h[2] ;original vector, segment
mov DS,AX
mov AX,2513h ;set interrupt vector to DS:DX
int DOS_CALL
pop DS
push DS
mov DX,word ptr ES:old_28h ;original vector, offset
mov AX,word ptr ES:old_28h[2];original vector, segment
mov DS,AX
mov AX,2528h ;set interrupt vector to DS:DX
int DOS_CALL
pop DS
display lptx_gone ;inactivated
jmp bail_out
;------------------------------------------------------------------------
;
; displays the status of each of the three line printers
;
stat proc near
; display each LPTx with a message "not redirected"
; or redirected to <filename>
push AX
push BX
push DX
push SI
push DI
display stat_stat
stat_1: mov BX,offset lpt1 ;first printer
mov stat_ptr,'1'
display stat_lp
cmp ES:[BX].active,ON ;are we active?
je stat_1_a ;yes
display stat_off
jmp short stat_2
stat_1_a:
mov SI,BX ;base
add SI,offset lpt1.filen ;offset
mov DI,offset stat_fn
stat_1_lp:
mov AL,ES:[SI]
mov [DI],AL
inc SI
inc DI
cmp AL,NULL ;loop till a null byte is found
jne stat_1_lp
mov byte ptr [DI],CR
inc DI
mov byte ptr [DI],LF
inc DI
mov byte ptr [DI],DOLLAR
display stat_dir ;display file name
stat_2:
mov BX,offset lpt2 ;second printer
mov stat_ptr,'2'
display stat_lp
cmp ES:[BX].active,ON ;are we active?
je stat_2_a ;yes
display stat_off
jmp short stat_3
stat_2_a:
mov SI,BX ;base
add SI,offset lpt1.filen ;offset
mov DI,offset stat_fn
stat_2_lp:
mov AL,ES:[SI]
mov [DI],AL
inc SI
inc DI
cmp AL,NULL ;loop till a null byte is found
jne stat_2_lp
mov byte ptr [DI],CR
inc DI
mov byte ptr [DI],LF
inc DI
mov byte ptr [DI],DOLLAR
display stat_dir ;display file name
stat_3: mov BX,offset lpt3 ;third printer
mov stat_ptr,'3'
display stat_lp
cmp ES:[BX].active,ON ;are we active?
je stat_3_a ;yes
display stat_off
jmp short stat_done
stat_3_a:
mov SI,BX ;base
add SI,offset lpt1.filen ;offset
mov DI,offset stat_fn
stat_3_lp:
mov AL,ES:[SI]
mov [DI],AL
inc SI
inc DI
cmp AL,NULL ;loop till a null byte is found
jne stat_3_lp
mov byte ptr [DI],CR
inc DI
mov byte ptr [DI],LF
inc DI
mov byte ptr [DI],DOLLAR
display stat_dir ;display file name
stat_done:
pop DI
pop SI
pop DX
pop BX
pop AX
ret
stat endp
;
cseg ends
%out EOF
end lptx